﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DirectZZT.Shared.Core;
#endregion

namespace DirectZZT.Shared.Scripting
{
    /// <summary>
    /// Provides facilities to instantiate scripts.
    /// </summary>
    public static class Script
    {
        #region Constants

        /// <summary>
        /// Defines the char that is used to denote a comment.
        /// </summary>
        public static readonly char CommentChar = '\'';
        /// <summary>
        /// Defines The default script cycle time (in milliseconds).
        /// </summary>
        public static readonly int DefaultCycle = (int)((16 * 2.5f) * 4);       // < this is 16 ms * 4 (four frames)

        #endregion

        /// <summary>
        /// Parses the script, ready to be used.
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        public static IScript Parse(string[] lines)
        {
            if (lines.Length >= 1 && lines[0].StartsWith("'ScriptType=Powerscript"))
            {
                return Parse(lines, ScriptLanguage.Powerscript);
            }
            else
            {
                return Parse(lines, ScriptLanguage.ZZToop);
            }
        }

        /// <summary>
        /// Parses the script, ready to be used.
        /// </summary>
        /// <param name="lines"></param>
        /// <param name="language">The language of the script.</param>
        /// <returns></returns>
        public static IScript Parse(string[] lines, ScriptLanguage language)
        {
            IScript script = null;

            // peek first line: what kind of script is this?
            switch (language)
            {
                case ScriptLanguage.Powerscript:
                    {
                        // TODO: make this dynamic!
                        var export = TypeManager.Instance.GetExports(typeof(IScript)).FirstOrDefault(t => t.Attribute.Alias == "Powerscript");
                        if (export.Type != null)
                        {
                            script = (IScript)Activator.CreateInstance(export.Type);
                        }
                    } break;
                case ScriptLanguage.ZZToop:
                    {
                        // TODO: make this dynamic!
                        var export = TypeManager.Instance.GetExports(typeof(IScript)).FirstOrDefault(t => t.Attribute.Alias == "ZZToop");
                        if (export.Type != null)
                        {
                            script = (IScript)Activator.CreateInstance(export.Type);
                        }
                    } break;
                default: break;
            }

            if (script == null)
            {
                Logging.GetLogging().Log(LoggingMessageType.Error, "Script", "", "Could not create instance of this script!");
                return null;
            }

            // sanity check: filter out all empty lines (what a nuissance) and lines that are appearantly comments
            List<string> lin = new List<string>(lines.Length);
            foreach (string line in lines)
            {
                if (line.Trim().Length > 0 && line[0] != Script.CommentChar)
                {
                    lin.Add(line);
                }
            }

            // that's all folks
            script.Script = lin.ToArray();

            return script;
        }

        /// <summary>
        /// Loads a script file from a stream.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static IScript LoadFrom(Stream stream)
        {
            List<string> script = new List<string>(32);

            // open ourselves a stream reader and take that output...
            using (StreamReader reader = new StreamReader(stream))
            {
                string line = null;
                while ((line = reader.ReadLine()) != null)
                {
                    if (line.Trim().Length > 0)
                    {
                        script.Add(line);
                    }
                }
            }
            // ... to parse the script
            return Parse(script.ToArray());
        }

    }
}
